package com.moro.lisp.tools;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Scanner;

import com.moro.lisp.JLispData;
import com.moro.lisp.JLispType;
import com.moro.lisp.os.Terminal;
import com.moro.lisp.typedefine.Atom;
import com.moro.lisp.typedefine.Cons;

public class Debug {
	/*
	 * 这个字段表示用来存储被调用实体数据的list集合
	 */
	private List<JLispData> callBodys;
	
	private int depth;
	
	private int currentDepth;
	
	private boolean allowInto;
	
	private JLispQueue calledQueue;
	
	/*
	 * 这个字段用来表示当前集合中值的个数，（注意是当前实时的个数，不能小于0）
	 */
	private int size;
	
	private boolean isDebug; //是否打印函数调用日志
	
	private boolean debug; //是否处于debug状态
	
	public Debug() {
		this.depth = 1;
		
		this.currentDepth = 0;
		
		this.allowInto = false;
		
		this.callBodys = new ArrayList<JLispData>();
		
		this.calledQueue = new JLispQueue();
		
		this.size = this.callBodys.size();
		
		this.isDebug = false;
		
		this.debug = false;
	}
	
	public void into(JLispData[] args, JLispData functionOrMacro, JLispData caller) {
		if(this.isDebug && !this.debug) {
			System.out.println();
			System.out.print("-->");
			Terminal.print(caller);
		}
		
		this.currentDepth += 1;
		if(this.debug) {
			if(this.currentDepth > this.depth) {
				if(this.allowInto) {
					this.depth = this.currentDepth;
					if(this.depth < 1) {
						this.depth = 1;
					}
					this.allowInto = false;
					
					System.out.println();
					if(0 < args.length) {
						Terminal.print(args[0]);
						for(int i = 1;i < args.length;i++) {
							System.out.print(" ");
							if(10 == i) {
								System.out.print("...");
								break;
							}
							Terminal.print(args[i]);
						}
					}
					System.out.print("-->");
					Terminal.print(caller);
					System.out.println();
					
					Scanner sc = new Scanner(System.in);
					String code = sc.next();
					if("into".equalsIgnoreCase(code)) {
						this.allowInto = true;
					}else if("next".equalsIgnoreCase(code)) {
						this.closeDebugMode();
					}
				}
			}else {
				this.allowInto = false;
				
				System.out.println();
				if(0 < args.length) {
					Terminal.print(args[0]);
					for(int i = 1;i < args.length;i++) {
						System.out.print(" ");
						if(10 == i) {
							System.out.print("...");
							break;
						}
						Terminal.print(args[i]);
					}
				}
				System.out.print("-->");
				Terminal.print(caller);
				System.out.println();
				
				Scanner sc = new Scanner(System.in);
				String code = sc.next();
				if("into".equalsIgnoreCase(code)) {
					this.allowInto = true;
				}else if("next".equalsIgnoreCase(code)) {
					this.closeDebugMode();
				}
			}
		}
		
		this.callBodys.add(functionOrMacro);
//		this.callBodys.add(caller);
		
		this.size = this.callBodys.size();
	}
	
	public void outfrom(JLispData functionOrMacro, JLispData executeAns, JLispData caller) {
		
		
		this.callBodys.remove(--this.size);
		if(this.isDebug && !this.debug) {
			System.out.println();
			Terminal.print(caller);
			System.out.print("==>");
			Terminal.print(executeAns);
		}
		
		if(this.debug) {
			if(this.currentDepth <= this.depth) {
				System.out.println();
				Terminal.print(caller);
				System.out.print("==>");
				Terminal.print(executeAns);
				
				
				this.depth = this.currentDepth;
				if(this.depth < 1) {
					this.depth = 1;
				}
				
				this.allowInto = false;
			}
		}
		
		this.currentDepth -= 1;
		
		this.calledQueue.add(new FunMacAndAns(functionOrMacro, executeAns));
	}
	
	public JLispData curCall() {
		if(0 == this.size) {
			return null;
		}
		return this.callBodys.get(this.size - 1);
	}
	
	public void startDebug() {
		this.isDebug = true;
	}
	
	public void closeDebug() {
		this.isDebug = false;
	}
	
	public void startDebugMode() {
		if(this.debug) {
			return;
		}
		this.debug = true;
		this.depth = this.currentDepth;
	}
	
	public void closeDebugMode() {
		this.debug = false;
	}
	
	public boolean isLogMode() {
		return this.isDebug;
	}
	
	public boolean isDebugMode() {
		return this.debug;
	}
	
	public void printStackTrace() {
		System.out.println();
		for(int i = this.size - 1;i >= 0;i--) {
			Terminal.print(this.callBodys.get(i));
			System.out.println();
		}
	}
}
